package master选举.zkclient实现;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * author Veng Su
 * email  1344114844@qq.com
 * date   18-9-17 下午3:26
 */
/*
原理简介：利用临时节点的失去连接后临时节点会被删除。
当主节点的客户端失去连接时，临时节点被删除，开启新的选举，由存在连接的客户端去写入一个新的节点。
如果写入成功，则代表这个节点是主节点，选举完成。
 */
public class MasterSelector {
    private ZkClient zkClient;

    private final static String MASTER_PATH = "/master";//需要争抢的节点

    private IZkDataListener dataListener;  //注册节点内容变化的监听

    private UserCenter server;//普通节点服务器
    private UserCenter master;//主服务器

    private static boolean isRunning = false;

    private ScheduledExecutorService scheduled= Executors.newScheduledThreadPool(1);

    public MasterSelector(UserCenter server,ZkClient zkClient) {
        this.server = server;
        this.zkClient=zkClient;

        //初始化时注册监听内容
        this.dataListener = new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {

            }

            @Override
            public void handleDataDeleted(String s) throws Exception {
                //如果主服务器（主节点）被删除，则开始选举
                System.out.println(server.getMac_name()+"-----------------监测到主节点被删除----------------------------");
                Thread.sleep(200);
                chooseMaster();

            }
        };
    }

    //    开始选举
    public void start() {
        if (!isRunning){
            isRunning=true;
        }
        System.out.println(server.getMac_name()+"--------上线");
        zkClient.subscribeDataChanges(MASTER_PATH,dataListener);
        chooseMaster();
    }

    //    停止选举
    public void stop() {
        if (isRunning){
            isRunning=false;
            scheduled.shutdown();
            zkClient.unsubscribeDataChanges(MASTER_PATH,dataListener);
            releaseMaster();
        }
    }

    private void chooseMaster() {
        if (!isRunning) {
            System.out.println("当前服务没有启动");
            return;
        }
        try {
            System.out.println(server.getMac_name()+"---"+server.getMac_id()+"---正在抢");
            zkClient.createEphemeral(MASTER_PATH, server);
            master = server;//把创建成功的server赋值给master
            System.out.println(master.getMac_name() + ":是master");

//            定时器
//            master释放，出现故障
            scheduled.schedule(()->{
                System.out.println("release master");
                releaseMaster();
            }, 5, TimeUnit.SECONDS);


        } catch (ZkNodeExistsException e) {
//           表示master已存在
//            e.printStackTrace();
            UserCenter userCenter = zkClient.readData(MASTER_PATH,true);

            if (userCenter ==null){
                chooseMaster();
            }else {
                master=userCenter;
            }

        }
    }

    //    释放锁,删除节点，故障模拟

    private void releaseMaster() {
//判断当前节点是否是主节点，如果是，则执行：因为只有主节点才需要释放。
        if (isMaster()){
            zkClient.deleteRecursive(MASTER_PATH);
            System.out.println("delete");

        }
    }

    //    判断节点是否是master
    private boolean isMaster() {
        UserCenter userCenter=zkClient.readData(MASTER_PATH);
        if (userCenter.getMac_name().equals(server.getMac_name())){
            master=userCenter;
            return true;
        }
        return false;

    }


}
